package com.vteba.ocr;

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.imageio.stream.ImageOutputStream;

import com.jhlabs.image.ChannelMixFilter;
import com.jhlabs.image.CurvesFilter;
import com.jhlabs.image.DiffusionFilter;
import com.jhlabs.image.DitherFilter;
import com.jhlabs.image.ExposureFilter;
import com.jhlabs.image.GrayFilter;
import com.jhlabs.image.GrayscaleFilter;
import com.jhlabs.image.MapColorsFilter;
import com.jhlabs.image.ThresholdFilter;

public class ClearImageHelper {

	public static void main(String[] args) throws IOException {

		File testDataDir = new File("C:\\Program Files (x86)\\Tesseract-OCR\\");
		final String destDir = testDataDir.getAbsolutePath() + "/tmp";
		for (File file : testDataDir.listFiles()) {
			String name = file.getName();
			if (name.endsWith("bmp") || name.endsWith("jpg") || name.endsWith("png")) {
				//cleanImage(file, destDir);
				
//				ThresholdFilter filter = new ThresholdFilter();// 颜色阈值
				GrayscaleFilter filter = new GrayscaleFilter();// 转换成灰度图
				//GrayFilter filter = new GrayFilter();//图像灰度
//				CurvesFilter filter = new CurvesFilter();// 调整曲线的图像
//				DiffusionFilter filter = new DiffusionFilter();//抖动
//				DitherFilter filter = new DitherFilter();//有序抖动
				//ExposureFilter filter = new ExposureFilter();//改变图像的曝光度
//				ChannelMixFilter filter = new ChannelMixFilter();//混合rgb通道
				//MapColorsFilter filter = new MapColorsFilter();//颜色替换
				
				BufferedImage bufferedImage = ImageIO.read(file);
				BufferedImage dst = new BufferedImage(bufferedImage.getWidth(), bufferedImage.getHeight(), BufferedImage.TYPE_INT_RGB);
				
				filter.filter(bufferedImage, dst);
				
				File file2 = new File(destDir, file.getName());
				FileOutputStream fos = new FileOutputStream(file2);
				ImageOutputStream imageOut = ImageIO.createImageOutputStream(fos);
				ImageIO.write(dst, "JPEG", imageOut);
			}
		}

		
		//
		
//		File testDataDir2 = new File("C:\\Program Files (x86)\\Tesseract-OCR\\tmp");
//		final String destDir2 = testDataDir.getAbsolutePath() + "\\tmp";
//		for (File file : testDataDir2.listFiles()) {
//			String name = file.getName();
//			if (name.endsWith("bmp") || name.endsWith("jpg") || name.endsWith("png")) {
//				cleanImage(file, destDir2);
//			}
//		}
	}

	/**
	 * 
	 * @param sfile
	 *            需要去噪的图像
	 * @param destDir
	 *            去噪后的图像保存地址
	 * @throws IOException
	 */
	public static void cleanImage(File sfile, String destDir) throws IOException {
		File destF = new File(destDir);
		if (!destF.exists()) {
			destF.mkdirs();
		}

		BufferedImage bufferedImage = ImageIO.read(sfile);
		int h = bufferedImage.getHeight();
		int w = bufferedImage.getWidth();

		// 灰度化
		int[][] gray = new int[w][h];
		for (int x = 0; x < w; x++) {
			for (int y = 0; y < h; y++) {
				int argb = bufferedImage.getRGB(x, y);
				// 图像加亮（调整亮度识别率非常高）
				int r = (int) (((argb >> 16) & 0xFF) * 1.1 + 30);
				int g = (int) (((argb >> 8) & 0xFF) * 1.1 + 30);
				int b = (int) (((argb >> 0) & 0xFF) * 1.1 + 30);
				if (r >= 255) {
					r = 255;
				}
				if (g >= 255) {
					g = 255;
				}
				if (b >= 255) {
					b = 255;
				}
				gray[x][y] = (int) Math
						.pow((Math.pow(r, 2.2) * 0.2973 + Math.pow(g, 2.2) * 0.6274 + Math.pow(b,
								2.2) * 0.0753), 1 / 2.2);
			}
		}

		// 二值化
		int threshold = ostu(gray, w, h);
		BufferedImage binaryBufferedImage = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_BINARY);
		for (int x = 0; x < w; x++) {
			for (int y = 0; y < h; y++) {
				if (gray[x][y] > threshold) {
					gray[x][y] |= 0x00FFFF;
				} else {
					gray[x][y] &= 0xFF0000;
				}
				binaryBufferedImage.setRGB(x, y, gray[x][y]);
			}
		}

		// 矩阵打印
//		for (int y = 0; y < h; y++) {
//			for (int x = 0; x < w; x++) {
//				if (isBlack(binaryBufferedImage.getRGB(x, y))) {
//					System.out.print("*");
//				} else {
//					System.out.print(" ");
//				}
//			}
//			System.out.println();
//		}

		ImageIO.write(binaryBufferedImage, "jpg", new File(destDir, sfile.getName()));
	}

	public static boolean isBlack(int colorInt) {
		Color color = new Color(colorInt);
		if (color.getRed() + color.getGreen() + color.getBlue() <= 300) {
			return true;
		}
		return false;
	}

	public static boolean isWhite(int colorInt) {
		Color color = new Color(colorInt);
		if (color.getRed() + color.getGreen() + color.getBlue() > 300) {
			return true;
		}
		return false;
	}

	public static int isBlackOrWhite(int colorInt) {
		if (getColorBright(colorInt) < 30 || getColorBright(colorInt) > 730) {
			return 1;
		}
		return 0;
	}

	public static int getColorBright(int colorInt) {
		Color color = new Color(colorInt);
		return color.getRed() + color.getGreen() + color.getBlue();
	}

	public static int ostu(int[][] gray, int w, int h) {
		int[] histData = new int[w * h];
		// Calculate histogram
		for (int x = 0; x < w; x++) {
			for (int y = 0; y < h; y++) {
				int red = 0xFF & gray[x][y];
				histData[red]++;
			}
		}

		// Total number of pixels
		int total = w * h;

		float sum = 0;
		for (int t = 0; t < 256; t++)
			sum += t * histData[t];

		float sumB = 0;
		int wB = 0;
		int wF = 0;

		float varMax = 0;
		int threshold = 0;

		for (int t = 0; t < 256; t++) {
			wB += histData[t]; // Weight Background
			if (wB == 0)
				continue;

			wF = total - wB; // Weight Foreground
			if (wF == 0)
				break;

			sumB += (float) (t * histData[t]);

			float mB = sumB / wB; // Mean Background
			float mF = (sum - sumB) / wF; // Mean Foreground

			// Calculate Between Class Variance
			float varBetween = (float) wB * (float) wF * (mB - mF) * (mB - mF);

			// Check if new maximum found
			if (varBetween > varMax) {
				varMax = varBetween;
				threshold = t;
			}
		}

		return threshold;
	}
}
